package org.benjamin.lending.service.impl;

import java.math.BigDecimal;
import java.sql.Timestamp;

import org.apache.logging.log4j.Logger;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.logging.log4j.LogManager;
import org.benjamin.lending.domain.entity.*;
import org.benjamin.lending.domain.entity.MemberMoneyLog.InpOut;
import org.benjamin.lending.domain.entity.MemberMoneyLog.Type;
import org.benjamin.lending.domain.entity.WithdrawalsLog.Status;
import org.benjamin.lending.domain.form.MemberForm;
import org.benjamin.lending.domain.form.WithdrawForm;
import org.benjamin.lending.domain.form.WithdrawIndex;
import org.benjamin.lending.repository.*;
import org.benjamin.lending.service.MemberInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

@Service
public class MemberInfoServiceImpl implements MemberInfoService {

	protected final Logger logger = LogManager.getLogger();

	@Autowired
	private MemberInfoRepository memberInfoRepository;

	@Autowired
	private RechargeLogRepository rechargeLogRepository;

	@Autowired
	private MemberMoneyRepository memberMoneyRepository;

	@Autowired
	private MemberMoneyLogRepository memberMoneyLogRepository;

	@Autowired
	private MemberStatusRepository memberStatusRepository;

	@Autowired
	private WithdrawalsLogRepository withdrawlsLogRepository;

	@Override
	public Page<MemberInfo> findMemberPage(MemberForm memberForm, Pageable pageable) {
		return this.memberInfoRepository.findAll(pageable);
	}

	@Override
	public MemberInfo findMemberDetails(String username) {
		return this.memberInfoRepository.findByUsername(username);
	}

	@Override
	public MemberInfo findMemberDetails(Integer id) {
		return this.memberInfoRepository.findOne(id);
	}

	@Override
	public MemberStatus findMemberStatusObject(String username) {
		MemberInfo memberInfo = this.memberInfoRepository.findByUsername(username);
		MemberStatus memberStatus = this.memberStatusRepository.findOne(memberInfo.getId());
		if (memberStatus == null) {
			memberStatus = new MemberStatus();
			memberStatus.setId(memberInfo.getId());
			this.memberStatusRepository.save(memberStatus);
		}
		return memberStatus;
	}

	@Override
	public WithdrawalsLog withdrawApply(MemberInfo memberInfo, WithdrawForm form, BigDecimal serviceCharge) {
		logger.info("记录用户提现数据到数据库中，用户提现金额：{}，手续费:{}", form.getAmount(), serviceCharge);
		WithdrawalsLog withdrawalsLog = new WithdrawalsLog();
		withdrawalsLog.setAmount(form.getAmount());
		withdrawalsLog.setFee(serviceCharge);
		withdrawalsLog.setMemberInfo(memberInfo);
		withdrawalsLog.setStatus(Status.SEND);
		this.withdrawlsLogRepository.save(withdrawalsLog);
		return withdrawalsLog;
	}

	@Override
	public void withdrawAccept(TransactType transactType,Integer id,String bankCode,String bankName) {
		WithdrawalsLog withdrawalsLog = this.withdrawlsLogRepository.findOne(id);
		Assert.notNull(withdrawalsLog, "获取到提现记录是NULL,提现记录的标识码是:" + id);
		if (withdrawalsLog.getStatus().equals(Status.SEND)) {
			withdrawalsLog.setStatus(Status.PROCESS);
			withdrawalsLog.setProcessTime(new Timestamp(System.currentTimeMillis()));
			withdrawalsLog.setBankName(bankName);
			withdrawalsLog.setBankCode(bankCode);
			this.withdrawlsLogRepository.save(withdrawalsLog);
			this.recordMoneyChange(Type.USER_WITHDRAW_ACCEPT, withdrawalsLog.getAmount(), withdrawalsLog.getMemberInfo(), transactType, withdrawalsLog.getId());
			return;
		}
		logger.info("当前提现记录已经登记了处理中");
	}

	@Override
	public void withdrawReceived(TransactType transactType,Integer id) {
		WithdrawalsLog withdrawalsLog = this.withdrawlsLogRepository.findOne(id);
		if (withdrawalsLog.getStatus().equals(Status.PROCESS)) {
			withdrawalsLog.setStatus(Status.SUCCESS);
			withdrawalsLog.setFinshTime(new Timestamp(System.currentTimeMillis()));
			this.withdrawlsLogRepository.save(withdrawalsLog);
			this.recordMoneyChange(Type.USER_WITHDRAW_RECEIVED, withdrawalsLog.getAmount(), withdrawalsLog.getMemberInfo(), transactType, withdrawalsLog.getId());
			return;
		}
		logger.info("当前提现记录已经登记完成");
	}

	@Override
	public void withdrawFail(Integer id, String message) {
		WithdrawalsLog withdrawalsLog = this.withdrawlsLogRepository.findOne(id);
		withdrawalsLog.setFinshTime(new Timestamp(System.currentTimeMillis()));
		withdrawalsLog.setDescribe(message);
		this.withdrawlsLogRepository.save(withdrawalsLog);
	}
	
	

	@Override
	public boolean checkRealName(String username) {
		MemberInfo memberInfo = this.memberInfoRepository.findByUsername(username);
		MemberStatus memberStatus = this.memberStatusRepository.findOne(memberInfo.getId());
		if(memberStatus != null) {
			try {
				if(memberStatus.getRealName() == null) {
					throw new NullPointerException();
				}
			}catch(NullPointerException e) {
				memberStatus.setRealName(0);
			}
			return memberStatus.getRealName() == 1;
		}else {
			memberStatus = new  MemberStatus();
			memberStatus.setId(memberInfo.getId());
			this.memberStatusRepository.save(memberStatus);
		}
		return false;
	}



	@Value("${moneyLog.recharge.message}")
	private String MONEY_RECHARGE_MESSAGE;

	@Override
	public void recordMoneyChange(MemberMoneyLog.Type type,BigDecimal affectMoney,MemberInfo memberInfo,TransactType transactType, Object rel) {
		
		MemberMoneyLog memberMoneyLog = new MemberMoneyLog();
		memberMoneyLog.setCreateTime(new Timestamp(System.currentTimeMillis()));
		memberMoneyLog.setAffectMoney(affectMoney);
		memberMoneyLog.setType(type);
		memberMoneyLog.setTransactType(transactType);
		memberMoneyLog.setMemberInfo(memberInfo);
		
		MemberMoney memberMoney = this.memberMoneyRepository.findByMemberInfoAndTransactType(memberInfo, transactType);
		if(memberMoney == null) {
			memberMoney = new MemberMoney();
			memberMoney.setMemberInfo(memberInfo);
			memberMoney.setTransactType(transactType);
			logger.warn("当前用户{}可能是第一次资金操作，而数据库没有创建对应的及资金账户记录，在此创建新的资金账户记录",memberInfo.getUsername());
		}
		memberMoneyLog.setBalaceMoney(memberMoney.getBalance());
		memberMoneyLog.setFreezeMoney(memberMoney.getFreeze());
		
		//
		Integer relId = null;
		
		switch (type) {
		case USER_RECHARGE:
			RechargeLog rechargeLog;
			if(rel instanceof Integer) {
				Integer id = (Integer)rel;
				rechargeLog = this.rechargeLogRepository.findOne(id);
			}else if(rel instanceof RechargeLog) {
				rechargeLog = (RechargeLog)rel;
			}else {
				throw new IllegalArgumentException("关联充值记录对象无法找到！");
			}
			
			String info = this.MONEY_RECHARGE_MESSAGE.replace("#MONEY#", affectMoney.toString()).replace("#BANKCODE#", rechargeLog.getBankCode());
			memberMoneyLog.setInfo(info);
			memberMoneyLog.setInpOut(InpOut.INPUT);
			memberMoneyLog.setRel(rechargeLog.getId());
			
			memberMoney.setBalance(memberMoney.getBalance().add(affectMoney));
			memberMoney.setBalanceRecharge(memberMoney.getBalanceRecharge().add(affectMoney));
			memberMoneyLog.setBalaceRechargeAffect(affectMoney);
			break;
		case USER_WITHDRAW_ACCEPT:
			if(rel instanceof Integer) {
				relId = (Integer)rel;
			}
			Assert.notNull(relId, "未能查询到提现记录");
			memberMoneyLog.setInfo(MONEY_RECHARGE_MESSAGE);
			memberMoneyLog.setInpOut(InpOut.OUTPUT);
			memberMoneyLog.setRel(relId);
			memberMoneyLog.setFreezeMoney(affectMoney);
			
			//TODO 提现顺序未能修改
			memberMoney.setBalance(memberMoney.getBalance().subtract(affectMoney));
			memberMoney.setBalanceRecharge(memberMoney.getBalanceRecharge().subtract(affectMoney));
			memberMoney.setFreeze(memberMoney.getFreeze().add(affectMoney));
		break;
		case USER_WITHDRAW_RECEIVED:
			if(rel instanceof Integer) {
				relId = (Integer)rel;
			}
			Assert.notNull(relId, "未能将相关的对象转换成功");
			memberMoneyLog.setInfo(MONEY_RECHARGE_MESSAGE);
			memberMoneyLog.setRel(relId);
			memberMoneyLog.setInpOut(InpOut.OUTPUT);
			
			memberMoney.setFreeze(memberMoney.getFreeze().subtract(affectMoney));
			break;
		default:
			break;
		}
		this.memberMoneyRepository.save(memberMoney);
		this.memberMoneyLogRepository.save(memberMoneyLog);
		
	}

	@Override
	public Page<WithdrawalsLog> findWithdrawLogPage(WithdrawIndex withdrawForm, Pageable pageable) {
		return this.withdrawlsLogRepository.findAll(pageable);
	}

}
